Introducing Kotlin/Native

Kotlin for Android, iOS and beyond

by taylorcyang

table of content

  1. What is Kotlin/Native
  2. comparesion of Cross-Platform tech
  3. How it works
  4. How to use
  5. What's happening under the hood

1. What is Kotlin/Native

K/N platforms

from KotlinConf 2018

K/N targets

K/N targets

K/N targets whatever LLVM targets!

Answer

Kotlin/Native is:

  1. Kotlin compiles to native targets(without vm)
  2. A target of Kotlin lang.
  3. with all kotlin features
  4. K/N itself is not multiplatform
  5. K/N makes Kotlin multiplatform possible.

Who's using it

K/N is still in beta

multi-platform solutions

Solution Type
  1. C++
  2. J2ObjC
  3. Multi-OS Engine
  4. Kotlin
Infrastructure
  1. React/Native
  2. Weex
  3. Xamarin
Language + UI Binding
  1. Flutter
Language + Framework

cpp

share cpp code with Android and iOS

Pros:

  1. High performance
  2. compat executable

Cons:

  1. Hard to learn/write
  2. Android: requeire JNI
  3. iOS: requires Objective-C++ bridge
  4. manual memory manangement
  5. all other CPP disadvantage

Wechat | Tencent Drive

J2ObjC

Translate Java code to OC

Pros:

  1. Java

Cons:

  1. ARC on Java (@Weak)
  2. large executable size (Java stdlib) 30+MB

Multi-OS Engine

Bundle an ART VM into iOS app

Pros:
  1. Java
  2. Fully functional JVM
  3. GC

Cons:

  1. Extrimly large executable size(JVM and java stdlib) 80MB

PS: Xamarin is similar.

R/N & Weex & Xarmain

Language + Binding

Pros:

  1. JavaScript? (C#?)
  2. Front end community

Cons:

  1. Large executable size (V8)
  2. Performance
  3. Native UI knowledge

Flutter

Language + Framework

Pros:

  1. Dart VM
  2. MethodChannel
  3. UI performance

Cons:

  1. binary size & RAM consumption
  2. goes pure dart?
  3. platform API call
  4. how long can it survive?

to sum up

soultion cons
C++
J2Objc
Multi-OS Engine
1. none-unified coding style
2. large stdlib(VM) to bundle
R/N Weex Flutter learn 3 platforms (2+1)

How K/N works

  1. compiler
  2. runtime
  3. stdlib
  4. interop with C/Objective-C

Kotlin compiler

Compiler

Kotlin/Native runtime

  • memory management
  • object memory layout
  • concurrency model
  • virtual method call

memory management

ARC with cycle collector

automated reference counter with a cycle collector to collect cyclical garbage.

C/C++ OC/Swift Java K/N
manual half-auto auto auto

concurrency model

  1. can't share mutable object across threads
  2. freeze() marks an object tree inmmutable, thus sharing across threads
  3. DetachedObjectGraph to transfer ownership to other thread, thus mutable.

Still under constructing...
coroutint isn't truly concurrent, yet

Official doc

Kotlin stdlib and extension

  1. kotlin stdlib
  2. kotlinx.serialization
    • json 2. protobuf 3. etc...
    • extensible (jce)
  3. kotlinx.coroutines
  4. kotlinx.io
  5. kotlinx.atomicfu
  6. ktor

interop with Java

Kotlin on JVM platform

You know What is it.

interop with OC/Swift

  1. K/N call OC methods

  2. K/N extends OC class (and/or impl oc protocol)

  3. passing K/N reference to OC

  4. and vice versa

  5. withiout performance penalty

Official Document

K/N Swit interop -- method

kotlin

NSRunLoop.mainRunLoop().performBlock { block.run() }

swift

presenter = StoryContentPresenter(storyId: detailStory.id)
presenter.onLoadData = { [unowned self] data in
    self.renderData(data)
    return KotlinUnit()
}

OC

SharedCodeStoryContentPresenter *presenter = 
    [[SharedCodeStoryContentPresenter: alloc] initWithStoryId: story.id]]

K/N Swift interop -- passing ref

// create a kotlin instance
let block = LinkedList.Companion().createACallable()
block(KotlinInt.init(value: 42)) // and use it

All kotlin class inherits KotlinBase which inherits NSObject


let list = LinkedList() // kotlin class
list.put(e: Junk()) // Junk is swift class

OC class must inhert from NSObject to pass to kotlin

K/N Swift interop -- class

kotlin extends OC class

@ExportObjCClass
class ViewController : UIViewController {
    @OverrideInit constructor(coder: NSCoder) : super(coder)
    @ObjCOutlet lateinit var button: UIButton
    @ObjCAction fun buttonPressed() {
        label.text = "Konan says: 'Hello, ${textField.text}!'"
    }
}

swift extends Kotlin class

open class AKotlinClass {
    open fun helloWorld(greet: String) { ... }
}
class SwiftClassInheritedFromKotlinClass : AKotlinClass {
    override func helloWorld(greet: String) { ... }
}

K/N Swit interop -- import K/N to OC

  1. K/N compiles to standard OC framework

  2. import framework into OC/Swift

framework

K/N Swit interop -- import OC to K/N

cinterop to the rescue

// UIKit.def
depends = CFNetwork ...
language = Objective-C
package = platform.UIKit
headers = UIKit/UIKit.h
linkerOpts = -framework UIKit
...

cinterop create Kotlin binding for C and OC/Swift

K/N Swift interop -- iOS framework

K/N has already defined cinterop definition files

xx

And you can write your own cinterop definition file, which is easy

How to use K/N

  1. quick look
  2. multiplatform project
  3. expect & actual
  4. clean architecture

Quick look

fun main() {
    println("Hello Kotlin World!")
}

~: kotlinc kmain.kt
~: konanc kmain.kt -o kmain
~: ls -lh
total 1680
-rw-r--r--  1 young  staff   687B Nov 26 10:54 KmainKt.class
-rwxr-xr-x  1 young  staff   829K Nov 26 10:52 kmain.kexe
-rw-r--r--  1 young  staff    50B Nov 26 10:50 kmain.kt
~: java KmainKt
Hello Kotlin World!
~: ./kmain.kexe
Hello Kotlin World!

multiplatform project

.
├── SharedCode
│   └── src
│       ├── androidMain
│       ├── androidTest // unit test
│       ├── commonMain
│       ├── commonTest  // unit test
│       ├── iOSMain
│       └── iOSTest     // unit test
├── android
└── ios

code of Kotlin-mpp

Stup a MP project

project structure

project-structure

expect & actual

What do you expect? And what I have.

expect & actual

SharedCode
└── src
    ├── androidMain
    │   └── actuals.kt
    ├── commonMain
    │   └── expects.kt
    └── iOSMain
        └── actuals.kt

Seperate implementation and declaration

Similar to interface, but differs!

function expect-actual

commmon-exepcts

expect suspend fun httpGet(url: String): String

anriod-actual

actual suspend fun httpGet(url: String): String = withContext(MyDispatchers.Worker) {
    val httpConn = URL(url).openConnection() as HttpURLConnection
    httpConn.connect()
    httpConn.inputStream.readBytes().toString(Charsets.UTF_8)
    // ...
}

ios-actual

actual suspend fun httpGet(url: String): String {
    val request = NSMutableURLRequest()
    request.setHTTPMethod("GET")
    request.setURL(NSURL(string = url))
    // ...
}

class expect-actual

commmon-exepcts

expect object MyDispatchers {
    val Main: CoroutineDispatcher
}

anriod-actual

actual object MyDispatchers {
    actual val Main: CoroutineDispatcher = Dispatchers.Main
}

ios-actual

actual object MyDispatchers {
    actual val Main: CoroutineDispatcher = object : CoroutineDispatcher() {
        override fun dispatch(context: CoroutineContext, block: Runnable) {
            NSRunLoop.mainRunLoop().performBlock { block.run() } } }
}

expect-actual vs interface

  1. both need common decliration
  2. both need different implmentation
  3. expect-actual is static
  4. interface is dynamic
  5. expect-actual don't need depedency injection

Architecture

GOAL

  1. totally seperate UI and businiss logic
  2. UI goes native (platform api)
  3. businiss logic goes common (no platform api)

clean architecture

Architecture of multiplatform dev in kotlin

structurein detail

TO SUM UP Kotlin/Native

Pros:

  1. multi-platform
  2. full kotlin language feature
  3. easy interop wich OC/Swift/C
  4. compact runtime and stdlib
  5. enforce clean architecture

Cons:

  1. concurrency model is currently mistery
  2. coroutine isn't cuncurrent for now (2018/11/29)

thanks